/* Vecmath.

   Copyright (C) 2001, 2002, 2003 Stefan Maierhofer.

   Written by Stefan Maierhofer <sm@cg.tuwien.ac.at>

   This file is part of Vecmath.

   Vecmath is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   Vecmath is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Vecmath; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */

using System;
using NUnit.Framework;

namespace Vecmath
{
    /// <summary>
    /// Box2D.
    /// </summary>
    public struct Box2D
    {

        public static Box2D Empty = new Box2D(Vecmath.HUGE_PNT2D, -Vecmath.HUGE_PNT2D);

        public Box2D(Pnt2D lower, Pnt2D upper)
        {
            this.lower = lower;
            this.upper = upper;
        }

        public Pnt2D Lower
        {
            get { return lower; }
            set { lower = value; }
        }

        public Pnt2D Upper
        {
            get { return upper; }
            set { upper = value; }
        }

        public Pnt2D LL { get { return new Pnt2D(lower._x[0], lower._x[1]); } }
        public Pnt2D LU { get { return new Pnt2D(lower._x[0], upper._x[1]); } }
        public Pnt2D UL { get { return new Pnt2D(upper._x[0], lower._x[1]); } }
        public Pnt2D UU { get { return new Pnt2D(upper._x[0], upper._x[1]); } }

        public int MinDim
        {
            get
            {
                Vec2D dim = upper - lower;
                return (dim[0] < dim[1]) ? 0 : 1;
            }
        }

        public int MaxDim
        {
            get
            {
                Vec2D dim = upper - lower;
                return (dim[0] > dim[1]) ? 0 : 1;
            }
        }

        public double Minimum
        {
            get
            {
                Vec2D dim = upper - lower;
                return (dim[0] < dim[1]) ? dim[0] : dim[1];
            }
        }

        public double Maximum
        {
            get
            {
                Vec2D dim = upper - lower;
                return (dim[0] > dim[1]) ? dim[0] : dim[1];
            }
        }

        public bool IsInside(Pnt2D p)
        {
            return lower < p && upper > p;
        }

        public bool IsInsideOrOnBorder(Pnt2D p)
        {
            return lower <= p && upper >= p;
        }

        public bool IsOnBorder(Pnt2D p)
        {
            return IsInsideOrOnBorder(p) && !IsInside(p);
        }

        public bool IsInside(Box2D b)
        {
            return lower < b.lower && upper > b.upper;
        }

        public bool IsInsideOrOnBorder(Box2D b)
        {
            return lower <= b.lower && upper >= b.upper;
        }

        public bool IsOnBorder(Box2D b)
        {
            return IsInsideOrOnBorder(b) && !IsInside(b);
        }

        public int Relation(int dim, float val)
        {
            if (upper[dim] < val) return -1;
            if (lower[dim] > val) return 1;
            return 0;
        }

        public static Box2D operator+(Box2D b, Pnt2D p)
        {
            return new Box2D(Pnt2D.Min(b.lower, p), Pnt2D.Max(b.upper, p));
        }

        public static Box2D operator+(Box2D b, Box2D c)
        {
            return new Box2D(Pnt2D.Min(b.lower, c.lower), Pnt2D.Max(b.upper, c.upper));
        }

        public static bool ApproxEqual(Box2D a, Box2D b)
        {
            return
                Vecmath.ApproxEquals(a.Lower, b.Lower) &&
                Vecmath.ApproxEquals(a.Upper, b.Upper);
        }

        public override bool Equals(object obj)
        {
            Box2D x = (Box2D)obj;
            return (lower == x.Lower && upper == x.Upper);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode ();
        }

        public override string ToString()
        {
            return "Box2D(" + lower + ", " + upper + ")";
        }

        internal Pnt2D lower;
        internal Pnt2D upper;


    }


    [TestFixture]
    public class Box2DTest
    {
        [Test]
        public void InitTest()
        {
            Box2D b = new Box2D(new Pnt2D(1,2), new Pnt2D(4,5));
            Assert.AreEqual(new Pnt2D(1,2), b.Lower);
            Assert.AreEqual(new Pnt2D(4,5), b.Upper);

            Assert.AreEqual(new Pnt2D(1,2), b.LL);
            Assert.AreEqual(new Pnt2D(1,5), b.LU);
            Assert.AreEqual(new Pnt2D(4,2), b.UL);
            Assert.AreEqual(new Pnt2D(4,5), b.UU);
        }

        
    }

}
